/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package tetrisdamage;

import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import java.nio.ByteBuffer;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;

/**
 *
 * @author Zheltoukhov
 */
public class Engine {

    // We need to strongly reference callback instances.
    private GLFWErrorCallback errorCallback;
    private KeyCallback keyCallback;
    private MouseButtonCallback mouseButtonCallback;

    // The window handle
    private long window;

    public Engine() throws Exception {
        ConfigManager conf = new ConfigManager();
        Integer width = conf.getWindowWidth();
        Integer height = conf.getWindowHeight();
        Boolean isFullscreen = conf.isFullscreen();
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if (glfwInit() != GL11.GL_TRUE) {
            throw new IllegalStateException("Unable to initialize GLFW");
        }

        // Configure our window
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable

        // Get the resolution of the primary monitor
        ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        if (width == -1 && height == -1) {
            width = GLFWvidmode.width(vidmode);
            height = GLFWvidmode.height(vidmode);
        } else if (width < -1 && height < -1) {
            throw new Exception("Window's size failed.");
        }

        if (isFullscreen) {
            window = glfwCreateWindow(width, height, "Tetris Damage", glfwGetPrimaryMonitor(), NULL);
            if (window == NULL) {
                throw new RuntimeException("Failed to create the GLFW window");
            }
        } else {
            window = glfwCreateWindow(width, height, "Tetris Damage", NULL, NULL);
            if (window == NULL) {
                throw new RuntimeException("Failed to create the GLFW window");
            }
            // Center our window
            glfwSetWindowPos(
                    window,
                    (GLFWvidmode.width(vidmode) - width) / 2,
                    (GLFWvidmode.height(vidmode) - height) / 2
            );
        }

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, keyCallback = new KeyCallback());
        glfwSetMouseButtonCallback(window, mouseButtonCallback = new MouseButtonCallback());

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);
        // Make the window visible
        glfwShowWindow(window);
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the ContextCapabilities instance and makes the OpenGL
        // bindings available for use.
        GLContext.createFromCurrent();
        // Set the clear color
        glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
    }

    public void close() {
        try {
            glfwSetWindowShouldClose(window, GL_TRUE);
            glfwDestroyWindow(window);
            keyCallback.release();
        } finally {
            // Terminate GLFW and release the GLFWerrorfun
            glfwTerminate();
            errorCallback.release();
        }
    }

    public boolean isClose() {
        return glfwWindowShouldClose(window) == GL_TRUE;
    }

    public void update() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

        glfwSwapBuffers(window); // swap the color buffers

        // Poll for window events. The key callback above will only be
        // invoked during this call.
        glfwPollEvents();
    }

    public boolean isKeyPressed(int code) {
        return keyCallback.getKey() == code;
    }

}
